package com.spark.gaea.utils;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;

public class Base58 {
	public static final char[] ALPHABET;
	private static final int[] INDEXES;

	public static String encode(byte[] input) {
		if (input.length == 0) {
			return "";
		}
		int zeroCount;
		for (input = copyOfRange(input, 0, input.length), zeroCount = 0;
			 zeroCount < input.length && input[zeroCount] == 0; ++zeroCount) {}
		final byte[] temp = new byte[input.length * 2];
		int j = temp.length;
		int startAt = zeroCount;
		while (startAt < input.length) {
			final byte mod = divmod58(input, startAt);
			if (input[startAt] == 0) {
				++startAt;
			}
			temp[--j] = (byte) Base58.ALPHABET[mod];
		}
		while (j < temp.length && temp[j] == Base58.ALPHABET[0]) {
			++j;
		}
		while (--zeroCount >= 0) {
			temp[--j] = (byte) Base58.ALPHABET[0];
		}
		final byte[] output = copyOfRange(temp, j, temp.length);
		try {
			return new String(output, "US-ASCII");
		} catch (UnsupportedEncodingException e) {
			throw new RuntimeException(e);
		}
	}

	public static byte[] decode(final String input) throws IllegalArgumentException {
		if (input.length() == 0) {
			return new byte[0];
		}
		final byte[] input2 = new byte[input.length()];
		for (int i = 0; i < input.length(); ++i) {
			final char c = input.charAt(i);
			int digit58 = -1;
			if (c < '\u0080') {
				digit58 = Base58.INDEXES[c];
			}
			if (digit58 < 0) {
				throw new IllegalArgumentException("Illegal character " + c + " at " + i);
			}
			input2[i] = (byte) digit58;
		}
		int zeroCount;
		for (zeroCount = 0; zeroCount < input2.length && input2[zeroCount] == 0; ++zeroCount) {}
		final byte[] temp = new byte[input.length()];
		int j = temp.length;
		int startAt = zeroCount;
		while (startAt < input2.length) {
			final byte mod = divmod256(input2, startAt);
			if (input2[startAt] == 0) {
				++startAt;
			}
			temp[--j] = mod;
		}
		while (j < temp.length && temp[j] == 0) {
			++j;
		}
		return copyOfRange(temp, j - zeroCount, temp.length);
	}

	public static BigInteger decodeToBigInteger(final String input) throws IllegalArgumentException {
		return new BigInteger(1, decode(input));
	}

	private static byte divmod58(final byte[] number, final int startAt) {
		int remainder = 0;
		for (int i = startAt; i < number.length; ++i) {
			final int digit256 = number[i] & 0xFF;
			final int temp = remainder * 256 + digit256;
			number[i] = (byte) (temp / 58);
			remainder = temp % 58;
		}
		return (byte) remainder;
	}

	private static byte divmod256(final byte[] number58, final int startAt) {
		int remainder = 0;
		for (int i = startAt; i < number58.length; ++i) {
			final int digit58 = number58[i] & 0xFF;
			final int temp = remainder * 58 + digit58;
			number58[i] = (byte) (temp / 256);
			remainder = temp % 256;
		}
		return (byte) remainder;
	}

	private static byte[] copyOfRange(final byte[] source, final int from, final int to) {
		final byte[] range = new byte[to - from];
		System.arraycopy(source, from, range, 0, range.length);
		return range;
	}

	static {
		ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz".toCharArray();
		INDEXES = new int[128];
		for (int i = 0; i < Base58.INDEXES.length; ++i) {
			Base58.INDEXES[i] = -1;
		}
		for (int i = 0; i < Base58.ALPHABET.length; ++i) {
			Base58.INDEXES[Base58.ALPHABET[i]] = i;
		}
	}
}
